let path = require('path');
let formidable = require('formidable');
let StringDecoder = require('string_decoder').StringDecoder;
let typeis = require('type-is');
let File = require('formidable/lib/file');

formidable.IncomingForm.prototype.handlePart = function (part) {
    let self = this;

    if (part.filename === undefined) {
        let value = '';
        let decoder = new StringDecoder(this.encoding);

        part.on('data', function (buffer) {
            self._fieldsSize += buffer.length;
            if (self._fieldsSize > self.maxFieldsSize) {
                self._error(new Error('maxFieldsSize exceeded, received ' + self._fieldsSize + ' bytes of field data'));
                return;
            }
            value += decoder.write(buffer);
        });

        part.on('end', function () {
            self.emit('field', part.name, value);
        });
        return;
    }

    this._flushing++;

    let ext = path.extname(part.filename);
    let file = {
        name: part.filename,
        mime: part.mime,
        hash: self.hash,
        ext: ext,
        size: 0,
        binaryBuff: undefined
    };

    this.emit('fileBegin', part.name, file);

    let _buff = '';

    part.on('data', function (buffer) {
        if (buffer.length === 0) {
            return;
        }
        self.pause();
        file.size += buffer.length;
        _buff += buffer.toString('binary');
        self.resume();
    });

    part.on('end', function () {
        file.binaryBuff = _buff;
        self._flushing--;
        self.emit('file', part.name, file);
        self._maybeEnd();
    });
};

exports = module.exports = formParser;

function formParser(options) {
    options = options || {};
    return function (req, res, next) {
        if (!typeis.hasBody(req) || req._body) {
            return next();
        }
        let _multipart = multipart(options);

        if (typeis(req) === 'multipart/form-data') { // form 表单提交 图片
            _multipart(req, res, next);
        } else {
            next();
        }
    };
}

// 表单
function multipart(options) {
    options = extend({
        uploadDir: 'dev/null',
        keepExtensions: true,
        hash: 'md5'
    }, options);
    return function multipartParser(req, res, next) {
        let form = new formidable.IncomingForm();
        let data = [];
        let done;

        Object.keys(options).forEach(function (key) {
            form[key] = options[key];
        });
        form.parse(req, function (err, fields, files) {
            req._body = true;
            req.body = extend(fields, files);
            next();
        });
    };
}

function extend(source, target) {
    if (!source) source = {};
    if (!target) return source;
    for (let k in target) {
        source[k] = target[k];
    }
    return source;
}
